const axios = require('axios');
const webpack = require('webpack');
const path = require('path');
const ReactSSR = require('react-dom/server');
const MemoryFs = require('memory-fs');
const proxy = require('http-proxy-middleware');

// getTemplate用来获取打包后的模板（内存中）
const getTemplate = () => new Promise((resolve, reject) => {
  // http去获取dev-server中的index.html
  axios.get('http://127.0.0.1:2333/public/index.html')
    .then((res) => {
      resolve(res.data);
    }).catch(reject);
});

const NativeModule = require('module');
const vm = require('vm');
const serverConfig = require('../../build/webpack.config.server');

// `(function(exports, require, module, __finename, __dirname){ ...bundle code })`
const getModuleFromString = (bundle, filename) => {
  const m = { exports: {} };
  const wrapper = NativeModule.wrap(bundle);
  const script = new vm.Script(wrapper, {
    filename,
    displayErrors: true,
  });
  const result = script.runInThisContext();
  result.call(m.exports, m.exports, require, m);
  return m;
};


// node环境中启动一个webpack 来获取打包后的server-entry.js
const mfs = new MemoryFs();

// 服务端使用webpack
const serverCompiler = webpack(serverConfig);
serverCompiler.outputFileSystem = mfs;
let serverBundle;
serverCompiler.watch({}, (err, stats) => {
  if (err) throw err;
  stats = stats.toJson();
  stats.errors.forEach(err => console.error(err));
  stats.warnings.forEach(warn => console.warn(warn));

  // 获取bundle文件路径
  const bundlePath = path.join(
    serverConfig.output.path,
    serverConfig.output.filename,
  );
  console.log('bundlePath------', bundlePath);
  const bundle = mfs.readFileSync(bundlePath, 'utf8');
  const m = getModuleFromString(bundle, 'server-entry.js');
  serverBundle = m.exports.default;
});

module.exports = function (app) {
// http 代理：所有通过/public访问的 都代理到http://localhost:2333
  app.use('/public', proxy({
    target: 'http://127.0.0.1:2333',
  }));
  app.get('*', (req, res, next) => {
    if (!serverBundle) {
      return res.send('waiting for compile, refresh later');
    }
    getTemplate().then((template) => {
      const content = ReactSSR.renderToString(serverBundle);
      res.send(template.replace('<!-- app -->', content));
    }).catch(next);
  });
};
